﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using SharePoint.Sunbox.Sandbox.Core;
using SharePoint.Sunbox.Sandbox.Resources;

namespace SharePoint.Sunbox.Sandbox.DataViewWebPart
{
    public class XslDataEditorPart : EditorPart
    {
        private const string FolderPath = "Style Library/Sunbox/SunboxDataView/XSL";
        private readonly Label _lblError;
        private readonly HiddenField _xslData;

        public XslDataEditorPart()
        {
            _xslData = new HiddenField();
            _lblError = new Label { ForeColor = Color.Red };
        }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            string webUrl = SPContext.Current.Site.RootWeb.Url;

            Controls.Add(_xslData);

            Controls.Add(
                new LiteralControl(
                    string.Format(
                        "<link rel='stylesheet' type='text/css' href='{0}/Style%20Library/SunBox/Scripts/fancybox/jquery.fancybox.css' />",
                        webUrl)));

            /*  SCRIPTS  */
            ReferencePrevalidatedScript("JSON",
                                        string.Format("{0}/Style%20Library/Sunbox/SunboxDataView/Scripts/json2.js",
                                                      webUrl));
            ReferencePrevalidatedScript("$.fancybox",
                                        string.Format(
                                            "{0}/Style%20Library/SunBox/Scripts/fancybox/jquery.fancybox.pack.js",
                                            webUrl));
            ReferenceLanguagePack(Properties.Language, webUrl);
            Controls.Add(
                new LiteralControl(
                    string.Format(
                        "<script type='text/javascript' src='{0}/Style%20Library/SunBox/SunboxDataView/Scripts/sunbox.dataview.xsleditorpart.js'></script>",
                        webUrl)));

            Controls.Add(_lblError);

            string containerId = Guid.NewGuid().ToString();
            Controls.Add(new LiteralControl(string.Format("<div id='{0}'></div>", containerId)));
            Controls.Add(
                new LiteralControl(string.Format(
                    "<script>$('#{0}').xslsourceeditorpart({{controlid:'{1}', lang: '{2}'}});</script>", containerId,
                    _xslData.ClientID, Properties.Language)));
        }

        private void ReferencePrevalidatedScript(string objectToValidate, string scriptPath)
        {
            Controls.Add(new LiteralControl(string.Format(
                @"<script>if (typeof ({0}) == ""undefined"") {{
                                                                document.write(""<script"" + "" src='{1}'><"" + ""/script>"");
                                                                }}
                                                            </script>",
                objectToValidate, scriptPath)));
        }

        private void ReferenceLanguagePack(string language, string webUrl)
        {
            Controls.Add(new LiteralControl(string.Format(
                @"<script>if (typeof (SunboxDataView.lang) == ""undefined"" || typeof(SunboxDataView.lang.{0}) == ""undefined"") {{
                                                                document.write(""<script"" + "" src='{1}/Style%20Library/SunBox/SunboxDataView/Scripts/lang/{0}.js'><"" + ""/script>"");
                                                                }}
                                                            </script>",
                language, webUrl)));
        }

        public override bool ApplyChanges()
        {
            try
            {
                var webpart = WebPartToEdit as DataViewWebPart;
                if (webpart == null) return false;

                if (_xslData.Value.Length <= 0)
                {
                    _lblError.Text = Properties.DataViewWebPartSpecifyXslTemplateText;
                    return false;
                }
                var xslSource = Helpers.DeserializeObject<XslSourceTemplate>(_xslData.Value);
                if (xslSource == null || string.IsNullOrEmpty(xslSource.Title))
                {
                    _lblError.Text = Properties.DataViewWebPartSpecifyXslTemplateText;
                    return false;
                }

                if (!xslSource.Title.EndsWith(".xsl"))
                    xslSource.Title += ".xsl";

                SaveXsl(xslSource.Title, xslSource.Xsl);
                webpart.XslSourceTitle = xslSource.Title;
                webpart.XslSourceLastModified = string.Empty;//reset xsl cache
            }
            catch (Exception ex)
            {
                _lblError.Text = string.Format("Error while saveing XSL template to style library: {0}", ex.Message);
                return true;
            }

            _lblError.Text = "";
            return true;
        }

        private void SaveXsl(string title, string xsl)
        {
            IEnumerable<string> files = GetFilesInFolder(FolderPath);
            string file = files.FirstOrDefault(f => f == title);
            var encoding = new UTF8Encoding(false);
            byte[] bytes = encoding.GetBytes(xsl);
            if (file != null)
            {
                SPFile spFile = SPContext.Current.Web.Site.RootWeb.GetFile(FolderPath + "/" + file);
                SPUser checkedOutByUser = spFile.CheckedOutByUser;
                if (checkedOutByUser == null)
                {
                    spFile.CheckOut();
                }
                else
                {
                    throw new Exception(string.Format("File '{0}' ejected by user '{1}'", file, checkedOutByUser.Name));
                }
                spFile.SaveBinary(bytes);
                spFile.CheckIn(String.Empty, SPCheckinType.MajorCheckIn);
                spFile.Update();
                return;
            }
            SPFile newFile = GetFolder(FolderPath).Files.Add(title, bytes);
            if (newFile.CheckOutType != SPFile.SPCheckOutType.None)
                newFile.CheckIn(String.Empty, SPCheckinType.MajorCheckIn); //check in file
            newFile.Update();
        }

        public override void SyncChanges()
        {
            var webpart = WebPartToEdit as DataViewWebPart;
            if (webpart == null) return;
            if (!string.IsNullOrEmpty(webpart.XslSourceTitle))
            {
                string xsl = GetXsl(webpart.XslSourceTitle);
                string title = webpart.XslSourceTitle;
                if (title.EndsWith(".xsl"))
                    title = title.Substring(0, title.Length - 4);
                _xslData.Value = Helpers.SerializeObject(new XslSourceTemplate { Title = title, Xsl = xsl });
            }
        }


        private IEnumerable<string> GetFilesInFolder(string folderPath)
        {
            SPFileCollection files;

            try
            {
                files = GetFolder(folderPath).Files;
            }
            catch (Exception)
            {
                yield break;
            }

            foreach (SPFile file in files)
            {
                yield return file.Name;
            }
        }

        private string GetXsl(string title)
        {
            if (string.IsNullOrEmpty(title))
                return string.Empty;
            try
            {
                SPFile spFile = SPContext.Current.Web.Site.RootWeb.GetFile(FolderPath + "/" + title);
                var encoding = new UTF8Encoding(false);
                byte[] bytes = spFile.OpenBinary();
                return encoding.GetString(bytes);
            }
            catch
            {
                return string.Empty;
            }
        }

        private SPFolder GetFolder(string folderPath)
        {
            return SPContext.Current.Web.Site.RootWeb.GetFolder(folderPath);
        }
    }
}